package com.central.apps.handler.project;

import com.central.app.common.base.BaseHandler;
import com.central.app.common.cache.CfgRedisCache;
import com.central.app.model.BizApp;
import com.central.app.service.HandlerService;
import com.central.apps.service.TableService;
import com.central.bizcommon.model.flow.FlowNode;
import com.central.bizcommon.model.flow.FlowOpinion;
import com.central.common.exception.service.ServiceException;
import com.central.common.web.PageResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;

/**
 * 处理立项管理业务逻辑
 *
 * @author lidachao
 * @date 2022/8/11
 */
@Component
@Slf4j
public class EstablishProjectHandler extends BaseHandler {

    @Autowired
    private HandlerService handlerService;
    @Autowired
    private TableService tableService;
    @Autowired
    private CfgRedisCache cfgRedisCache;

    @Override
    public String validateSave(String app, String objName, Map<String, Object> data) throws Exception {
        if ("gq_establishproject".equals(objName)) {
            String subjectNo = MapUtils.getString(data, "subjectno");
            Integer id = MapUtils.getInteger(data, "id");

            if (StringUtils.isNotEmpty(subjectNo) && id != null) {

                List<Map<String, Object>> list = handlerService.findBySql("select id from gq_establishproject where id != " + id + " and subjectno = '" + subjectNo + "'");
                if (CollectionUtils.isNotEmpty(list)) {
                    return "课题号已存在, 请重新编辑!";
                }
            }
        }
        return null;
    }

    @Override
    public Object operate(String app, String type, Map<String, Object> params) throws Exception {
        if ("getProSource".equals(type)) {
            String projecttype = MapUtils.getString(params, "projecttype");

            if (StringUtils.isEmpty(projecttype)) {
                return null;
            }

            String dictCode = "project_source";
            String sql = "select code, name from sys_dict where pid in (select id from sys_dict where code = '" + dictCode + "')";

            StringBuilder sb = new StringBuilder();
            if ("已立项".equals(projecttype)) {
                sb.append("'基金、预研类项目'");
                sb.append(",");
                sb.append("'横向类项目'");
            } else if ("待立项".equals(projecttype)) {
                sb.append("'纵向类项目'");
            }

            if (sb.length() > 0) {
                sql = sql + " and code not in (" + sb + ")";
            }

            // 查询数据字典信息
            List<Map<String, Object>> dictSql = handlerService.findBySql(sql);
            if (CollectionUtils.isNotEmpty(dictSql)) {
                return PageResult.<Map<String, Object>>builder().data(dictSql).code(0).count((long) dictSql.size()).build();
            }
        }
        return null;
    }

    @Override
    public void afterSave(String app, String objName, Map<String, Object> data, boolean isUpdate) throws Exception {
        String id = MapUtils.getString(data, "id");
        String pronum = MapUtils.getString(data, "pronum");

        if (StringUtils.isEmpty(pronum)) {
            Map<String, Object> proMap = new HashMap<>();

            // 生成项目编码
            handlerService.addBizNum("proaccountApp", "gq_proaccount", proMap);
            pronum = (String) proMap.get("pronum");

            // 更新项目编码
            handlerService.updateBySql("update gq_establishproject set pronum = '" + pronum + "' where id = " + id);
        }
    }

    @Override
    public void addFlowVar(String app, Long id, FlowNode flowNode, FlowOpinion op, Map<String, Object> variables) throws Exception {
        if (app.equals("establishprojectApp") && flowNode.getId().equals("sbdept_submit")) {
            String prosource = MapUtils.getString(variables, "prosource");
            if ("基础研究类".equals(prosource)) {
                variables.put("prosource", 0);
            } else {
                variables.put("prosource", 1);
            }
        }
    }

    @Override
    public String beforeExcuteFlow(String app, Long id, FlowNode flowNode, FlowOpinion op) throws Exception {
        // 校验是否编制了项目概算、项目资源、里程碑计划、产出计划以及项目目标等信息
        if ("capture".equals(flowNode.getId())) {
            Map<String, String> map = new HashMap<>(5);
            map.put("gq_epbudget", "项目概算");
            map.put("gq_epresources", "项目资源");
            map.put("gq_epmilestone", "里程碑计划");

            StringBuilder prompt = new StringBuilder();
            for (Map.Entry<String, String> entry : map.entrySet()) {
                List<Map<String, Object>> list = handlerService.findBySql("select id from " + entry.getKey() + " where epid = " + id);
                if (CollectionUtils.isEmpty(list)) {
                    prompt.append(entry.getValue()).append(",");
                }
            }

            if (StringUtils.isNotEmpty(prompt)) {
                prompt.deleteCharAt(prompt.length() - 1);
                prompt.append("等信息未维护, 请编制后再进行提交!");
                return prompt.toString();
            }
        }

        if ("complete1".equals(flowNode.getId()) || "complete2".equals(flowNode.getId())) {
            String esTableName = "gq_establishproject";
            String proTableName = "gq_proaccount";
            // 查询立项信息
            List<Map<String, Object>> list = handlerService.findBySql("select * from " + esTableName + " where id = " + id);

            if (CollectionUtils.isNotEmpty(list)) {
                Map<String, Object> map = list.get(0);

                // 根据来源表转化目标表对象
                Map<String, Object> proMap = tableService.convertMap(esTableName, proTableName, map, null, null);

                // TODO 状态控制
                proMap.put("prostatus", "进行中");
                proMap.put("proschedulestatus", "按期进行");
                proMap.put("costexestatus", "按期进行");

                // 插入项目台账信息
                BigInteger proId = (BigInteger) handlerService.insert(proTableName, proMap);

                // 更新立项信息
                handlerService.updateBySql("update " + esTableName + " set proid = " + proId + " where id = " + id);

                String subjectNo = MapUtils.getString(map, "subjectno");

                // 创建项目里程碑信息使用立项里程碑信息
                createMilestone(id, subjectNo, proId.longValue());
                // 创建项目经费概算信息使用立项经费概算信息
                createBudgetEstimate(id, subjectNo, proId.longValue());
                // 创建项目资源信息使用立项资源信息
                createResource(id, subjectNo, proId.longValue());
                // 创建产出计划
                // createOutputPlan(id, subjectNo, proId.longValue());
                // 创建初始项目计划
                // createPlan(proId, epMap);
                // 创建项目风险信息使用立项风险信息
                // createRisk(id, proid);
                // 附件转移到项目台账
                createAttachment(id, proId, app, "proaccountApp");
            }
        }

        return null;
    }

    /**
     * 创建项目里程碑信息使用立项里程碑信息
     *
     * @param epId      立项申请id
     * @param subjectNo 课题号
     * @param proId     项目id
     */
    private void createMilestone(Long epId, String subjectNo, Long proId) throws Exception {
        // 查询资源信息
        List<Map<String, Object>> list = handlerService.findBySql("select * from gq_epmilestone where epid = " + epId);

        if (CollectionUtils.isNotEmpty(list)) {
            Map<String, List<String>> convertMap = new HashMap<>();
            convertMap.computeIfAbsent("id", key -> new ArrayList<>()).add("mid");

            for (Map<String, Object> map : list) {
                Map<String, Object> addMap = tableService.convertMap("gq_epmilestone", "gq_pblmilestone", map, convertMap, null);

                if (addMap.isEmpty()) {
                    throw new ServiceException("表数据转换错误，请联系管理员!");
                }

                addMap.put("proid", proId);
                addMap.put("subjectno", subjectNo);
                addMap.put("status", "未开始");
                addMap.put("taskstatus", "未开始");
                addMap.put("progress", 0);
                addMap.put("unfinishprocess", 100);

                handlerService.insert("gq_pblmilestone", addMap);
            }
        }
    }

    /**
     * 创建项目风险信息使用立项风险信息
     *
     * @param id
     * @param proid
     */
    private void createRisk(Long id, BigInteger proid) throws Exception {
        // 查询风险信息
        String riskSql = "select id, risknum, riskdesc, remarks, createuser, createuserdesc from gq_riskhead where epid = " + id;
        List<Map<String, Object>> riskList = handlerService.findBySql(riskSql);

        if (CollectionUtils.isNotEmpty(riskList)) {
            for (Map<String, Object> riskMap : riskList) {
                Integer riskid = (Integer) riskMap.get("id");
                Map<String, Object> proriskMap = new HashMap<>();
                proriskMap.put("proid", proid);
                proriskMap.put("risknum", riskMap.get("risknum"));
                proriskMap.put("riskdesc", riskMap.get("riskdesc"));
                proriskMap.put("remarks", riskMap.get("remarks"));
                proriskMap.put("createuser", riskMap.get("createuser"));
                proriskMap.put("createuserdesc", riskMap.get("createuserdesc"));

                BigInteger proriskid = (BigInteger) handlerService.insert("gq_proriskhead", proriskMap);

                // 查询风险控制措施信息
                String riskmeasuresSql = "select measurenum, measuredesc, remarks, createuser, createuserdesc from gq_riskmeasures" +
                        " where riskid = " + riskid + " and epid = " + id;
                List<Map<String, Object>> riskmeasuresList = handlerService.findBySql(riskmeasuresSql);

                if (CollectionUtils.isNotEmpty(riskList)) {
                    for (Map<String, Object> riskmeasuresMap : riskmeasuresList) {
                        Map<String, Object> proriskmeasuresMap = new HashMap<>();
                        proriskmeasuresMap.put("proid", proid);
                        proriskmeasuresMap.put("riskid", proriskid);
                        proriskmeasuresMap.put("measurenum", riskmeasuresMap.get("measurenum"));
                        proriskmeasuresMap.put("measuredesc", riskmeasuresMap.get("measuredesc"));
                        proriskmeasuresMap.put("remarks", riskmeasuresMap.get("remarks"));
                        proriskmeasuresMap.put("createuser", riskmeasuresMap.get("createuser"));
                        proriskmeasuresMap.put("createuserdesc", riskmeasuresMap.get("createuserdesc"));

                        handlerService.insert("gq_proriskmeasures", proriskmeasuresMap);
                    }
                }
            }
        }
    }

    /**
     * 创建项目经费概算信息使用立项经费概算信息
     *
     * @param epId      立项申请id
     * @param subjectNo 课题号
     * @param proId     项目id
     */
    private void createBudgetEstimate(Long epId, String subjectNo, Long proId) throws Exception {
        // 查询立项经费概算信息
        List<Map<String, Object>> list = handlerService.findBySql("select * from gq_epbudget where epid = " + epId);

        if (CollectionUtils.isNotEmpty(list)) {
            Map<String, List<String>> convertMap = new HashMap<>();
            convertMap.computeIfAbsent("budgetamt", key -> new ArrayList<>()).add("usefulamt");
            convertMap.computeIfAbsent("budgetamt", key -> new ArrayList<>()).add("initbudgetamt");

            for (Map<String, Object> map : list) {
                // 根据来源表转化目标表对象
                Map<String, Object> addMap = tableService.convertMap("gq_epbudget", "gq_pblbestimate", map, convertMap, null);

                if (addMap.isEmpty()) {
                    throw new ServiceException("表数据转换错误，请联系管理员!");
                }

                addMap.put("proid", proId);
                addMap.put("subjectno", subjectNo);
                addMap.put("chgbudgetamt", 0);

                handlerService.insert("gq_pblbestimate", addMap);
            }
        }
    }

    /**
     * 创建项目计划信息使用立项计划信息
     *
     * @param proid
     * @param map
     */
    private void createPlan(BigInteger proid, Map<String, Object> map) throws Exception {
        String pronum = MapUtils.getString(map, "pronum");
        String subjectno = MapUtils.getString(map, "subjectno");

        Map<String, Object> proplanMap = new HashMap<>();

        proplanMap.put("proid", proid);
        proplanMap.put("pronum", pronum);
        proplanMap.put("subjectno", subjectno);
        proplanMap.put("recordId", 1);
        proplanMap.put("parentId", 0);
        proplanMap.put("tasknum", pronum + "1");
        proplanMap.put("parentLevel", -1);
        proplanMap.put("level", 0);
        proplanMap.put("name", map.get("proname"));
        proplanMap.put("unfinishprogress", 100);

        proplanMap.put("startTime", new Date());
        proplanMap.put("endTime", new Date());
        proplanMap.put("duration", 1);
        proplanMap.put("durationTimeUnit", "天");

        proplanMap.put("createuser", map.get("createuser"));
        proplanMap.put("createuserdesc", map.get("createuserdesc"));

        proplanMap.put("status", "未开始");
        proplanMap.put("taskstatus", "未开始");

        handlerService.insert("gq_scheduleplantask", proplanMap);
    }

    /**
     * 创建项目资源信息使用立项资源信息
     *
     * @param epId      立项申请id
     * @param subjectNo 课题号
     * @param proId     项目id
     */
    private void createResource(Long epId, String subjectNo, Long proId) throws Exception {
        // 查询资源信息
        List<Map<String, Object>> list = handlerService.findBySql("select * from gq_epresources where epid = " + epId);

        if (CollectionUtils.isNotEmpty(list)) {
            Map<String, List<String>> convertMap = new HashMap<>();
            convertMap.computeIfAbsent("id", key -> new ArrayList<>()).add("rid");

            for (Map<String, Object> map : list) {
                Map<String, Object> addMap = tableService.convertMap("gq_epresources", "gq_pblresources", map, convertMap, null);

                if (addMap.isEmpty()) {
                    throw new ServiceException("表数据转换错误，请联系管理员!");
                }

                addMap.put("proid", proId);
                addMap.put("subjectno", subjectNo);
                addMap.put("status", "可用");

                handlerService.insert("gq_pblresources", addMap);
            }
        }
    }

    /**
     * 创建产出计划
     *
     * @param epId      立项申请id
     * @param subjectNo 课题号
     * @param proId     项目id
     */
    private void createOutputPlan(Long epId, String subjectNo, Long proId) throws Exception {
        // 查询资源信息
        List<Map<String, Object>> list = handlerService.findBySql("select * from gq_esoutputplan where epid = " + epId);

        if (CollectionUtils.isNotEmpty(list)) {
            Map<String, List<String>> convertMap = new HashMap<>();
            convertMap.computeIfAbsent("id", key -> new ArrayList<>()).add("popid");

            for (Map<String, Object> map : list) {
                Map<String, Object> addMap = tableService.convertMap("gq_esoutputplan", "gq_pbloutputplan", map, convertMap, null);

                if (addMap.isEmpty()) {
                    throw new ServiceException("表数据转换错误，请联系管理员!");
                }

                addMap.put("proid", proId);
                addMap.put("subjectno", subjectNo);
                addMap.put("status", "未交付");

                handlerService.insert("gq_pbloutputplan", addMap);
            }
        }
    }

    /**
     * 创建项目台账附件
     *
     * @param id
     * @param proId
     */
    private void createAttachment(Long id, BigInteger proId, String fromApp, String toApp) throws Exception {
        // 查询项目登记附件信息
        List<Map<String, Object>> list = handlerService.findBySql("select * from tb_file where appname = '" + fromApp + "' and recordid = " + id);

        if (CollectionUtils.isNotEmpty(list)) {
            // 查询项目台账app信息
            BizApp bizApp = cfgRedisCache.getCacheApp(toApp);
            Long appId = bizApp.getId();

            for (Map<String, Object> map : list) {
                Map<String, Object> addMap = new HashMap<>();
                addMap.putAll(map);
                addMap.remove("fileid");
                addMap.put("appid", appId);
                addMap.put("appname", toApp);
                addMap.put("recordid", proId);

                handlerService.insert("tb_file", addMap);
            }
        }
    }
}
